home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / doom / tw212_sv.zip / TWQWSRC / HORN.QC < prev    next >
Text File  |  1997-05-07  |  15KB  |  482 lines

  1. // AIRG_MAIN_START
  2. /*
  3.  * File: horn.qc
  4.  * Date: 3 Jan 1997
  5.  *
  6.  * Description: Air gun main code.
  7.  *
  8.  *    Copyright and Distribution Permissions
  9.  *    --------------------------------------
  10.  *
  11.  *  The modifications included in this archive are Copyright 1997, the Evolve team.
  12.  *  The original QuakeC source is Copyright 1996, id software.
  13.  *
  14.  *  Authors MAY NOT use these modifications as a basis for commercially available work.
  15.  *
  16.  *  You may distribute this Quake modification in any electronic format as long as
  17.  *  all the files in this archive remain intact and unmodified and are distributed
  18.  *  together.
  19.  *
  20.  *  QuakeC, Model and artwork can be reused, but credit for the individual developers on
  21.  *   the AirFist team is required.
  22.  *
  23.  */
  24.  
  25. void(float nearAWall, float adjustForward, float adjustRight, float adjustUp, float positionRight, float spriteSpeed) hornBlastSprite;
  26. float (entity e) hornInfront;
  27. void() removeFlyMode;
  28.  
  29.  
  30. $cd id1/progs/s_ablast
  31.  
  32. $frame ablast1 ablast2 ablast3 ablast4 ablast5 ablast6
  33.  
  34.  
  35.  
  36. // The Main code for the AirFist that is called when the AirFist is fired.
  37. void() launch_horn =
  38. {
  39.     // Local variables used in the function
  40.   local entity e;
  41.   local vector delta;
  42.   local vector dir;
  43.   local float eSpeed;
  44.   local float dist;
  45.   local float percent;
  46.   local float ldmg;
  47.   local float nearAWall;
  48.  
  49.   // Constants used in the control of how the AirFist is works
  50.  
  51.   // Maximum strength of the AirFist.  The strength of the affected entity's
  52.   // movement is based on the distance from the center of the shot.
  53.   local float strength;
  54.   strength = 1000;  // full power of weapon
  55.  
  56.   // Maximum damage that can be incurred by the AirFist.  The actual entity's
  57.   // damage is based on the distance from the center of the shot.
  58.   local float inDamage;
  59.   inDamage = 20;  // full damage of weapon
  60.  
  61.   // Range of the AirFist blast.
  62.   local float inRange = 400;  // range of weapon
  63.  
  64.   // Number of bubbles generated when the AirFist is fired under water.
  65.   local float numBubbles = 3; // number of bubbles generated in the water
  66.  
  67.   // Recoil strength of the AirFist on the player that shot the weapon.
  68.   local float recoil = 300; // recoil strength of the gun
  69.  
  70.     // Reshot time for the airgun attack in seconds.
  71.     local float attackTime = 0.5;
  72.  
  73.     // Max number of times that the weapon can fired in a period of time.
  74.     local float maxFireRate = 5;
  75.  
  76.   // The maximum number of seconds that maxFireRate can fire in.  If the
  77.   // player has reached the maxFireRate in under the shotTimeout then all
  78.   // shots up to the shotTimeout are "failed" shots that don't do anything.
  79.   // e.g.  time to fire is 0.5 seconds.
  80.   //       maxFireRate is 5.
  81.   //       shotTimeout is 5.5 seconds.
  82.   //
  83.   // If 5 shots where fired at the max rate this would take 2.5 seconds.
  84.   // So there would be a 3 seconds wait before the AirFist will fire again.
  85.   // Any fire rate greater than 2.5 seconds will incure a smaller or no
  86.   // wait time.  Any shots fired in that wait time are "failed" shots that
  87.   // will do nothing.
  88.   local float shotTimeout = 5.5; // number of seconds for the maxFireRate
  89.  
  90.   // The AirFist fire codde:
  91.  
  92.   // By default, assume not near a wall.
  93.   nearAWall = 0;
  94.  
  95.   // Make such that all previous attack code completes.
  96.   if (!self.button0)
  97.     {player_run ();return;}  // Complete any other attacks first.
  98.  
  99.   // How long the fire time is.
  100.     self.attack_finished = time + attackTime;
  101.  
  102.   // First attack in the shotTimeout period
  103.   if(self.AIRG_FireCount == 0 || self.AIRG_Timeout < time)
  104.   {
  105.      // Set count and timeout length
  106.      self.AIRG_Timeout = time + shotTimeout + attackTime;
  107.      self.AIRG_FireCount = 1;
  108.   }
  109.   // Max Fire Rate reached, so this is a failed shot.
  110.   else if(self.AIRG_FireCount >= maxFireRate)
  111.   {
  112.     // play failed AirFist sound
  113.     if(self.waterlevel > 2)
  114.     {  // below the water, play under water sound
  115.       sound (self, CHAN_AUTO, "weapons/agwfail.wav", 1, ATTN_NORM);
  116.     }
  117.     else
  118.     { // play above water sound
  119.       sound (self, CHAN_AUTO, "weapons/agfail.wav", 1, ATTN_NORM);
  120.     }
  121.  
  122.     // play Failed AirFist animation
  123.     player_failedairgun1();
  124.     // and get out of here.
  125.     return;
  126.   }
  127.   else
  128.   {
  129.     // Count number of shots.
  130.     self.AIRG_FireCount = self.AIRG_FireCount + 1;
  131.   }
  132.  
  133.   if(self.waterlevel > 2) // if under water, change the variables
  134.   {
  135.       // reduced the range by %20
  136.     inRange = inRange * 0.80;
  137.  
  138.     // double the damage possible
  139.     inDamage = inDamage * 2;
  140.   }
  141.  
  142.   // Get all the entity's in the shot range
  143.   makevectors(self.v_angle);
  144.   e = findradius(self.origin, inRange);
  145.  
  146.   while (e)
  147.   {
  148.     // This is the exclusion code.  It excludes everything that is "Illegal" to
  149.     // move. eg. doors.
  150.  
  151.     // You may find this code looks funny,  it is the same is doing
  152.     // a if( exp & exp & exp & exp) but this way is faster.
  153.     //   (read the QuakeC manual for reason). 
  154.  
  155.     // only affect monsters and projectiles
  156.     // if (visible(e)) // must be visible AND
  157.     if (self.waterlevel > 2 || hornInfront(e)) // infront of self or anywhere in the water AND
  158.     if(e.movetype != MOVETYPE_NONE) // anything that can move
  159.     if(e.movetype != MOVETYPE_PUSH)
  160.     if(e.movetype != MOVETYPE_NOCLIP)
  161. // AIRG_EXCLUDE_START
  162.     if((e.AIRG_Flags & AIRG_EXCLUDEENTITY) != AIRG_EXCLUDEENTITY) // custom exclusion (like laser fire)
  163. // AIRG_EXCLUDE_END
  164.     if(e != self)  // but not myself!!
  165.     {
  166.       // if flying creature and movetype is step then change to fly
  167.       // NOTE: For some reason the normal quakeC, flying monsters has set a
  168.       //   movetype of MOVETYPE_STEP which means that changing the velocity
  169.       //   does not do anything.  Our workaround was to change the movetype
  170.       //   to MOVETYPE_FLY.  Flying monsters where then affected by
  171.       //   velocity.  In all our testing we found that this only affected the
  172.       //   entity's when they died.  When dead, they fall UP instead of down.
  173.       //   Other than this they did not seam to have any adverse affect.  If you
  174.       //   find that you have trouble with this code, let us know.
  175.       if(e.flags & FL_FLY)
  176.       {
  177.           if(e.movetype == MOVETYPE_STEP)
  178.           {
  179.           // set so we can affect velocity
  180.             e.movetype = MOVETYPE_FLY;
  181.  
  182.           // create a entity to remove the MOVETYPE_FLY when we are done with it.
  183.           //   the only problem with using this method is that while the entity
  184.           //   is dead but the tracker has not converted it back to STEP, the
  185.           //   entity will fall up until changed.  For a generic method, we
  186.           //   at the Evolve team can live with that.
  187.           e.AIRG_FlyTracker = spawn();
  188.           e.AIRG_Flags = e.AIRG_Flags + AIRG_STEPCONVERTEDTOFLY;
  189.           e.AIRG_FlyTracker.owner = e;
  190.           e.AIRG_FlyTracker.nextthink = time + 2;
  191.           e.AIRG_FlyTracker.think = removeFlyMode;
  192.  
  193.         }
  194.         else if(e.AIRG_Flags & AIRG_STEPCONVERTEDTOFLY)
  195.         {
  196.           // We have already converted this one, just extend the time to convert
  197.           e.AIRG_FlyTracker.nextthink = time + 2;
  198.         }
  199.       }
  200.  
  201.       // Calculate the distance from the entity.
  202.       delta = e.origin - self.origin + self.view_ofs;
  203.       dist = vlen(delta);
  204.  
  205.       // Convert distance to a percentage.
  206.       percent = (inRange - dist) / inRange;
  207.  
  208.       if (e.flags & FL_ONGROUND)
  209.       {
  210.           // If there on the ground, raise them up so that the velocity will
  211.         // take affect.
  212.  
  213.         // raise the bugger a bit
  214.         setorigin(e, e.origin + '0 0 1');
  215.  
  216.         // We biased the up direction when entity is on the ground.
  217.         // Looks cooler and small entitys (heath, etc) go somewhere instead
  218.         // of along the ground (cas there below the line of sight).
  219.  
  220.         // If on the ground, makem go up, up, and away
  221.         e.flags = e.flags - FL_ONGROUND;
  222.         if (delta_z < 0)
  223.           delta_z = delta_z / -2;
  224.         delta = delta * 0.7;
  225.  
  226.         if (delta_z < 100)
  227.           delta_z = 100;
  228.       }
  229.  
  230.       // calculate the velocity adjustment.
  231.       delta = normalize(delta);
  232.       delta = delta * percent * strength;
  233.  
  234.           if(self.waterlevel > 2) // if under water, change the blast amount
  235.       {
  236.         // if within 1/2 radius of the blast
  237.         if(percent >= 0.50)
  238.         if(e.classname == "player") // and is a player
  239.                 if (self.radsuit_finished == 0) // and not wearing bio
  240.         {
  241.           // that's it, no more air for him, chock time!!!
  242.                     self.air_finished = time - 1;
  243.         }
  244.  
  245.             if(hornInfront(e)) // infront of self
  246.         {
  247.           // reduce by %20
  248.           delta = delta * 0.80;
  249.         }
  250.         else // All other entity's are hit by water movement.
  251.         {
  252.           // reduce by %50
  253.             delta = delta * 0.50;
  254.  
  255.           // reduce the damage possible as well
  256.           percent = percent * 0.50;
  257.         }
  258.       }
  259.  
  260.       if(e.movetype == MOVETYPE_FLYMISSILE)
  261.       {
  262.         // If its a missile, change the direction but keep the same speed.
  263.         eSpeed = vlen(e.velocity);
  264.         e.velocity = normalize(delta) * eSpeed;
  265.       }
  266.       else
  267.       {
  268.         // Apply the velocity adjustment
  269.         e.velocity = e.velocity + delta;
  270.  
  271.         // calculate the damage amount
  272.         ldmg = percent * inDamage;
  273.  
  274.         // This section of code is to even of the "figure momentum add" in the
  275.         // T_Damage function that recoils damaged entity's away from the attacker.
  276.         //   NOTE:  If that section of code in T_Damage changesm then this will have to
  277.         //          change.
  278.         if(e.movetype != MOVETYPE_WALK) // to even out the T_Damage "figure momentum add"
  279.               {
  280.           dir = e.origin - (self.absmin + self.absmax) * 0.5;
  281.           dir = normalize(dir);
  282.           e.velocity = e.velocity + dir * ldmg * 8;
  283.         }
  284.  
  285.         // Apply damage to the entity.
  286.         T_Damage(e, self, self, ldmg);
  287.       }
  288.     }
  289.     e = e.chain;
  290.   }
  291.  
  292.   if(self.waterlevel > 2)
  293.   {  // below the water, produce bubbles
  294.      DeathBubbles(numBubbles);
  295.   }
  296.  
  297.   // check if near a wall
  298.   makevectors(self.v_angle);
  299.   dir = self.origin + self.view_ofs;
  300.   traceline (dir, dir + v_forward * 64, FALSE, self);
  301.  
  302.   if (trace_fraction != 1.0 && !trace_ent.takedamage)
  303.   {
  304.     nearAWall = 1;
  305.   }
  306.  
  307.   // Produce the AirFist fire blast sprites to the top left and right of the
  308.     // self's view.
  309.   //void(float nearAWall, float adjustForward, float adjustRight, float adjustUp, float positionRight, float spriteSpeed) hornBlastSprite =
  310.   if(self.waterlevel > 2)
  311.   {
  312.       // under water, go slower (%50 slower)
  313.       hornBlastSprite(nearAWall, 50, -50, 300, -20, 0.50);
  314.       hornBlastSprite(nearAWall, 50, 50, 300, 20, 0.50);
  315.   }
  316.   else
  317.   {
  318.     // above water, normal speed
  319.       hornBlastSprite(nearAWall, 50, -50, 300, -20, 1.0);
  320.       hornBlastSprite(nearAWall, 50, 50, 300, 20, 1.0);
  321.   }
  322.  
  323.   // recoil code
  324.   if (self.flags & FL_ONGROUND)
  325.   {
  326.        // If self on the ground, raise me up so that the velocity will
  327.     // take affect.
  328.  
  329.     // raise the bugger a bit
  330.     setorigin(self, self.origin + '0 0 1');
  331.     self.flags = self.flags - FL_ONGROUND;
  332.    }
  333.  
  334.   if(nearAWall)
  335.   {  // hit wall, Bounce based on the distance from the wall
  336.     recoil = recoil + (recoil * (1.0 - trace_fraction) * 3);
  337.   }
  338.  
  339.   // recoil self
  340.   self.velocity = self.velocity + v_forward * recoil * -1;
  341.  
  342.   if(self.waterlevel > 2)
  343.   {  // below the water, play under water sound
  344.     sound (self, CHAN_AUTO, "weapons/agwater.wav", 1, ATTN_NORM);
  345.   }
  346.   else
  347.   { // play above water sound
  348.     sound (self, CHAN_AUTO, "weapons/agfire.wav", 1, ATTN_NORM);
  349.   }
  350.  
  351.   // AirFist gun frame animation
  352.   player_airgun1();
  353. };
  354.  
  355.  
  356. // modification of infront() from ai.qc to be tighter
  357. float (entity e) hornInfront =
  358. {
  359.   local vector  vec;
  360.   local float    dot;
  361.  
  362.   makevectors (self.v_angle);
  363.   vec = normalize (e.origin - self.origin - self.view_ofs);
  364.   dot = vec * v_forward;
  365.  
  366.   if ( dot > 0.8 )
  367.   {
  368.     return TRUE;
  369.   }
  370.   return FALSE;
  371. };
  372.  
  373.  
  374.  
  375. // The AirFist fire blast sprite animation code.
  376.  
  377. void() run_ablast1   =[$ablast1, run_ablast2  ] {};
  378. void() run_ablast2   =[$ablast2, run_ablast3  ] {};
  379. void() run_ablast3   =[$ablast3, run_ablast4  ] {};
  380. void() run_ablast4   =[$ablast4, run_ablast5  ] {};
  381. void() run_ablast5   =[$ablast5, run_ablast6  ] {};
  382. void() run_ablast6   =[$ablast6, run_ablast1  ]
  383. {
  384.   remove(self);
  385. };
  386.  
  387.  
  388. // AirFist fire blast sprite animation under water (slowed down).
  389.  
  390. void() run_ablastWater1   =[$ablast1, run_ablastWater2  ] {};
  391. void() run_ablastWater2   =[$ablast1, run_ablastWater3  ] {};
  392. void() run_ablastWater3   =[$ablast2, run_ablastWater4  ] {};
  393. void() run_ablastWater4   =[$ablast2, run_ablastWater5  ] {};
  394. void() run_ablastWater5   =[$ablast3, run_ablastWater6  ] {};
  395. void() run_ablastWater6   =[$ablast3, run_ablastWater7  ] {};
  396. void() run_ablastWater7   =[$ablast4, run_ablastWater8  ] {};
  397. void() run_ablastWater8   =[$ablast4, run_ablastWater9  ] {};
  398. void() run_ablastWater9   =[$ablast5, run_ablastWater10 ] {};
  399. void() run_ablastWater10  =[$ablast5, run_ablastWater1  ]
  400. {
  401.   remove(self);
  402. };
  403.  
  404.  
  405.  
  406.  
  407. // Create a AirFist blast sprite
  408. void(float nearAWall, float adjustForward, float adjustRight, float adjustUp, float positionRight, float spriteSpeed) hornBlastSprite =
  409. {
  410.   local entity sprite, oldself;
  411.  
  412.   oldself = self;
  413.  
  414.   // Create the blast sprite and sets the variables.
  415.  
  416.   sprite = spawn();
  417.  
  418.   sprite.solid = SOLID_NOT;
  419.  
  420.   if(oldself.waterlevel > 2)
  421.   {  // below the water, play under water animation
  422.       sprite.movetype = MOVETYPE_NOCLIP;
  423.   }
  424.   else
  425.   {  // above water, play normal animation
  426.       sprite.movetype = MOVETYPE_BOUNCE;
  427.   }
  428.  
  429.   setmodel(sprite, "progs/s_ablast.spr");
  430.  
  431.   // Set the velocity based on the parameters passed
  432.   sprite.velocity =
  433.       v_forward * random() * adjustForward  +
  434.       v_right * random() * adjustRight +  // [MWH:01/12/97] Reduced left/right/up/down variablilty
  435.       v_up * random() * adjustUp;
  436.  
  437.   // set Speed
  438.   sprite.velocity = sprite.velocity * spriteSpeed;
  439.  
  440.   if(nearAWall)
  441.   {
  442.     // If near a wall, blast in face.
  443.     setorigin(sprite, self.origin + self.view_ofs + (v_right * positionRight));  // [MWH:01/12/97] raised origin a bit
  444.   }
  445.   else
  446.   {
  447.     // Not near a wall, so set start position in front of the player.
  448.     setorigin(sprite, self.origin + self.view_ofs + (v_forward * 30) + (v_right * positionRight));  // [MWH:01/12/97] raised origin a bit
  449.   }
  450.   setsize(sprite, '-8 -8 -8', '8 8 8');
  451.  
  452.   // play sprite animation.
  453.   self = sprite;
  454.  
  455.   if(oldself.waterlevel > 2)
  456.   {  // below the water, play under water animation
  457.       run_ablastWater1();
  458.   }
  459.   else
  460.   {  // above water, play normal animation
  461.       run_ablast1();
  462.   }
  463.  
  464.   self = oldself;
  465. };
  466.  
  467.  
  468.  
  469. void() removeFlyMode =
  470. {
  471.     // convert the movetype back to MOVETYPE_STEP cas we are finished with
  472.   // the velocity change (we should be anyway).
  473.   self.owner.movetype = MOVETYPE_STEP;
  474.   self.owner.AIRG_Flags = self.owner.AIRG_Flags - AIRG_STEPCONVERTEDTOFLY;
  475.  
  476.   // don't need self anymore, remove self.
  477.   remove(self);
  478. };
  479.  
  480. // AIRG_MAIN_END
  481.  
  482.